package com.gzz.demo.encryption;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
 *
 * HMAC_SHA1 Sign生成器
 * HMAC算法介绍：
 *      HMAC是密钥相关的哈希运算消息认证码（Hash-based Message Authentication Code）,HMAC运算利用哈希算法，
 *      以一个密钥和一个消息为输入，生成一个消息摘要作为输出。
 *
 * HMAC算法详解：
 *      HMAC使用公开函数和密钥产生一个固定长度的值作为认证标识，用这个标识鉴别消息的完整性。
 *      使用一个密钥生成一个固定大小的小数据块，即MAC，并将其加入到消息中，
 *      然后传输。接收方利用与发送方共享的密钥进行鉴别认证等。
 *
 */
public class HmacSha1 {
    private static final String HMAC_ALGORITHM = "HmacMD5"; // HmacSHA1

    /**
     * 随机生成密钥。
     * @return
     * @throws Exception
     */
    public static String initMacKey() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(HMAC_ALGORITHM);
        SecretKey secretKey = keyGenerator.generateKey();
        return Base64.getEncoder().encodeToString(secretKey.getEncoded());
    }

    /**
     * 使用 HMAC-SHA1 签名方法对data进行签名
     *
     * @param data 被签名的字符串
     * @param key 密钥
     * @return  加密后的字符串
     */
    public static String genHMAC(String data, byte[] key) {
        String result = null;
        try {
            //根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
            SecretKeySpec signinKey = new SecretKeySpec(key, HMAC_ALGORITHM);
            //生成一个指定 Mac 算法 的 Mac 对象
            Mac mac = Mac.getInstance(HMAC_ALGORITHM);
            //用给定密钥初始化 Mac 对象
            mac.init(signinKey);
            //完成 Mac 操作
            byte[] rawHmac = mac.doFinal(data.getBytes());
            result = Base64.getEncoder().encodeToString(rawHmac);
        } catch (NoSuchAlgorithmException e) {
            System.err.println(e.getMessage());
        } catch (InvalidKeyException e) {
            System.err.println(e.getMessage());
        }
        return result;
    }

    public static byte[] encryptHMAC(byte[] data, String key) throws Exception {

        SecretKey secretKey = new SecretKeySpec(Base64.getDecoder().decode(key), HMAC_ALGORITHM);
        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        mac.init(secretKey);
        return mac.doFinal(data);
    }


    /**
     * 测试
     * @param args
     */
    public static void main(String[] args) throws Exception {
        String inputStr="这是一个测试字符串aaabbbccc111222333" +
                "这是一个测试字符串" +
                "aaabbbccc111222333这是一个测试字符串aaabbbccc111222333" +
                "这是一个测试字符串aaabbbccc111222333这是一个测试字符串aaabbbccc111222333";
        System.out.println("原始数据："+inputStr);

        String key = initMacKey();
        System.out.println("Mac密钥:\n" + key);
        byte[] inputData = inputStr.getBytes();
        byte[] encryptData =encryptHMAC(inputData, key);
        System.out.println("HMAC:\n" + Base64.getEncoder().encodeToString(encryptData));
        BigInteger mac = new BigInteger(encryptData);
        System.out.println("HMAC:\n" + mac.toString(16));



        String genHMAC = genHMAC("111", "2222".getBytes());
        System.out.println(genHMAC.length()); //28
        System.out.println(genHMAC);  // O5fviq3DGCB5NrHcl/JP6+xxF6s=
    }
}
